package com.ruoyi.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
public class HttpUtils {


    public static String post(String url,Map<String,String> param) {
        // 创建默认的httpClient实例.
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 创建httppost
        HttpPost httppost = new HttpPost(url);
        // 创建参数队列
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        if(CollectionUtils.isEmpty(formparams)){
            for(Map.Entry<String,String> entry:param.entrySet()){
                formparams.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
            }
        }
        UrlEncodedFormEntity uefEntity;
        try {
            uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
            httppost.setEntity(uefEntity);
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                HttpEntity entity = response.getEntity();
                if(entity != null){
                    return EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接,释放资源
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static String get(String url) {
        // 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的)
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        String body = null;

        log.info("create httppost:" + url);
        HttpGet get = new HttpGet(url);
        body = invoke(httpClient, get);

        httpClient.getConnectionManager().shutdown();
        return body;
    }



    private static String invoke(CloseableHttpClient httpclient,
                                 HttpUriRequest httpost) {

        HttpResponse response = sendRequest(httpclient, httpost);
        String body = paseResponse(response);

        return body;
    }

    private static String paseResponse(HttpResponse response) {
        log.info("get response from http server..");
        HttpEntity entity = response.getEntity();

        log.info("response status: " + response.getStatusLine());
        String charset = EntityUtils.getContentCharSet(entity);
        log.info(charset);

        String body = null;
        try {
            body = EntityUtils.toString(entity);
            log.info(body);
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return body;
    }

    private static HttpResponse sendRequest(CloseableHttpClient httpclient,
                                            HttpUriRequest httpost) {
        log.info("execute post...");
        HttpResponse response = null;

        try {
            response = httpclient.execute(httpost);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }

    private static HttpPost postForm(String url, Map<String, String> params){

        HttpPost httpost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList <NameValuePair>();

        Set<String> keySet = params.keySet();
        for(String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }

        try {
            log.info("set utf-8 form entity to httppost");
            httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return httpost;
    }

    public static String doGet(String url){
        HttpType httpType = HttpType.getHttpType(url);
        HttpGet get = new HttpGet(url);
        if (httpType == HttpType.unknown) {
            return null;
        }
        return executeRequest(get,httpType,null);
    }

    private static String executeRequest(HttpRequestBase request, HttpType httpType,HttpHost host) {
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            switch (httpType) {
                case https:
                    client = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).build();
                    break;
                case http:
                    client = HttpClients.createDefault();
                    break;

            }
            RequestConfig requestConfig;
            RequestConfig.Builder builder = RequestConfig.custom()
                    .setConnectTimeout(60000).setConnectionRequestTimeout(60000)
                    .setSocketTimeout(60000);
            if (host == null) {
                requestConfig = builder.build();
            } else {
                requestConfig = builder.setProxy(host).build();
            }
            request.setConfig(requestConfig);
            response = client.execute(request);
            HttpEntity entity = response.getEntity();
            String returnValue = EntityUtils.toString(entity);
            return returnValue;
        } catch (IOException ex) {
            log.error("异常:请求异常", ex);
            return null;
        } finally {
            try {
                if (client != null) {
                    client.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error("错误:请求关闭异常", e);
            }
        }
    }

    /**
     * 创建SSL安全连接
     *
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslSf = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null
                    , (TrustStrategy) (chain, authType) -> true).build();
            sslSf = new SSLConnectionSocketFactory(sslContext);
        } catch (GeneralSecurityException e) {
            log.error("创建ssl安全连接异常!", e);
            throw new RuntimeException(e);
        }
        return sslSf;
    }

    /**
     * http类型枚举
     */
    public enum HttpType {
        http(0),
        https(1),
        unknown(2);

        private int value;

        HttpType(int value) {
            this.setValue(value);
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return this.name();
        }

        /**
         * 根据url获取请求类型
         *
         * @param url
         * @return
         */
        public static HttpType getHttpType(String url) {
            if (url.startsWith(HttpType.https.toString())) {
                return HttpType.https;
            } else if (url.startsWith(HttpType.http.toString())) {
                return HttpType.http;
            }
            return HttpType.unknown;
        }
    }
}
